#include "key_drv.h"

typedef struct {
    rcu_periph_enum rcu;
    uint32_t gpio;
    uint32_t pin;
} Key_GPIO_t;

static Key_GPIO_t Key_GPIO_arr[] = {
    {RCU_GPIOA, GPIOA, GPIO_PIN_0},
    {RCU_GPIOG, GPIOG, GPIO_PIN_13},
    {RCU_GPIOG, GPIOG, GPIO_PIN_14}
};

#define KEY_GPIO_ARR_MAX  (sizeof(Key_GPIO_arr)/sizeof(Key_GPIO_arr[0]))


typedef enum {
    RELEASE_STATUS = 0, //释放状态
    CONFIRM_STATUS,//消抖确认状态
    SHORT_STATUS,//短按状态
    LONG_STATUS,//长按状态
} KeyStatus;

typedef struct {
    KeyStatus keyStatus; // 按键状态
    uint64_t keyFirstPressTime;//按键第一次按下的时间
    uint8_t  keyPressTimes;//按键按下的次数
    uint64_t keyFirstReleseTime;//按键第一次释放的时间
} KeyInfoStruct;

static KeyInfoStruct KeyInfoArr[KEY_GPIO_ARR_MAX];


/**
 * @desc  : 按键初始化
 * @date  : 2025-03-25
 * @author: AnRui
 * @note  :
 */
void KeyDrvInit(void) {
    for (uint8_t i = 0; i < KEY_GPIO_ARR_MAX; i++) {
        rcu_periph_clock_enable(Key_GPIO_arr[i].rcu);
        gpio_init(Key_GPIO_arr[i].gpio, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_2MHZ, Key_GPIO_arr[i].pin);
    }
}



/**
 * @desc  : 按键状态扫描
 * @date  : 2025-03-25
 * @author: AnRui
 * @param : keyIndex - {参数说明}: 按键编号
 * @return: uint8_t
 * @note  : 根据按键编号 扫描该按键状态 返回按键状态码
 *     当前释放状态:
 *                 按下:
 *                     如果第一按下 转成消抖确认状态
 *                     如果第二次按下 当前时间-上一次释放时间 如果超过窗口时间 说明是短按状态结束  返回状态码
 *                 抬起:
 *                      不处理还是释放状态
 *
 *     确认消抖状态:
 *                按下:
 *                     当前时间第一次按下的时间 如果超过窗口时间 说明是短按状态开始
 *                抬起:
 *                      变为释放状态
 *
 *     短按状态:
 *               按下:
 *                    当前时间第一次按下的时间 如果超过窗口时间 说明是长按状态
 *
 *               抬起:
 *                   变为释放状态 按下次数+1
 *                                          第一次抬起 记录本次抬起时间
 *                                          第二次抬起 说明是双击状态
 *     长按状态:
 *             抬起: 变为释放状态 长按状态结束 返回长按状态码
 *
 *
 * 短按 双击 长按 都只是在释放后才返回该状态 因为只有释放了 才代表结束
 *
 *
 *
 * 释放状态->按下,转为确认态,记录时间1->确认状态 抬起 转为释放状态                                  ->短按状态   抬起 转为释放状态 记录释放时间                                ->长按状态 抬起 长按结束
 *           抬起,不处理                        按下 与时间1对比 超过短按时间 转为短按态,按下次数+1              按下 对比第一次按下的时间 是否超过长按时间,超过时间转为长按状态
 *
 *
 *
 *
 *
 *
 *
 */
static uint8_t KeyScan(uint8_t keyIndex) {
    FlagStatus keyCurStatus;
    uint64_t currentTime;
    keyCurStatus = gpio_input_bit_get(Key_GPIO_arr[keyIndex].gpio, Key_GPIO_arr[keyIndex].pin);

    switch (KeyInfoArr[keyIndex].keyStatus) {
    case RELEASE_STATUS:
        // 释放状态+第1次按下=确认状态
        if (!keyCurStatus) {
            KeyInfoArr[keyIndex].keyStatus = CONFIRM_STATUS;
            KeyInfoArr[keyIndex].keyFirstPressTime = GetSysRunTime();
        }
        // 如果当前时间-第一次释放的时间 大于双击时间 就不满足双击条件
        if (KeyInfoArr[keyIndex].keyPressTimes != 0) {
            currentTime = GetSysRunTime();
            if ((currentTime - KeyInfoArr[keyIndex].keyFirstReleseTime) > DOUBLE_TIME) {
                KeyInfoArr[keyIndex].keyPressTimes = 0;
                return keyIndex + 0x01; // 此时为短按状态
            }
        }
        break;

    case CONFIRM_STATUS: // 消抖确认
        if (!keyCurStatus) { //按键按下
            currentTime = GetSysRunTime();
            // 如果当前时间-按键按下的时间 超过确认时间窗口 确认为短按状态
            if ((currentTime - KeyInfoArr[keyIndex].keyFirstPressTime) > CONFIRM_TIME) {
                KeyInfoArr[keyIndex].keyStatus = SHORT_STATUS;
            }
        } else { // 按键释放
            KeyInfoArr[keyIndex].keyStatus = RELEASE_STATUS;
        }
        break;
    case SHORT_STATUS: //  短按状态：   继续判定是短按，还是双击，还是长按
        if (keyCurStatus) {   //按键抬起
            KeyInfoArr[keyIndex].keyStatus = RELEASE_STATUS;
            KeyInfoArr[keyIndex].keyPressTimes++;
            // 第一次
            if (KeyInfoArr[keyIndex].keyPressTimes == 1) {
                KeyInfoArr[keyIndex].keyFirstReleseTime = GetSysRunTime(); // 记录释放时间
                break;
            } else {
                currentTime = GetSysRunTime();
                if ((currentTime - KeyInfoArr[keyIndex].keyFirstPressTime) <= DOUBLE_TIME) {
                    KeyInfoArr[keyIndex].keyPressTimes = 0;
                    return (keyIndex + 0x51);
                }
            }
        } else { // 按键按下
            currentTime = GetSysRunTime();
            if ((currentTime - KeyInfoArr[keyIndex].keyFirstPressTime) >= LONGPRESS_TIME) {
                KeyInfoArr[keyIndex].keyStatus = LONG_STATUS;
            }
        }
        break;
    case LONG_STATUS: // 长按状态
        if (keyCurStatus) {// 按键抬起 长按结束
            KeyInfoArr[keyIndex].keyStatus = RELEASE_STATUS;
            return keyIndex + 0x81;
        }
        //继续按下 保持长按状态
        break;
    default:
        // 第一次检测 赋值为释放状态
        KeyInfoArr[keyIndex].keyStatus = RELEASE_STATUS;
        break;
    }
    // 没有检测到短按或长按状态
    return 0;
}


/**
 * @desc  : 实时获取按键状态码
 * @date  : 2025-03-25
 * @author: AnRui
 * @return: uint8_t
 * @note  :
 */
uint8_t GetKeyStatusCode(void) {
    uint8_t res = 0;
    for (uint8_t i = 0; i < KEY_GPIO_ARR_MAX; i++) {
        res = KeyScan(i);
        if (res != 0) {
            //					 printf("%02x",res);
            break;
        }
    }
    return res;
}
